package prev.mj.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * @author 马洁
 * @date 2020/4/8 - 9:50
 */
public class ObjectUtil {
    public static <T> T deepCopy(T originalObj) {
        return deepCopy(originalObj, true, false);
    }

    @SuppressWarnings("unchecked")
    public static <T> T deepCopy(T originalObj, boolean copyPrivate, boolean copyFather) {
        Class<?> cls = originalObj.getClass();

        T resultObj = null;
        try {
            resultObj = (T) cls.getConstructor().newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
            System.out.println("该类不能被实例化");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            System.out.println("非法操作");
        } catch (InvocationTargetException e) {
            e.printStackTrace();
            System.out.println("调用方法失败");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            System.out.println("没有这样的方法");
        }


        Field[] fields = copyFather?
                            cls.getFields():
                            cls.getDeclaredFields();

        if (copyPrivate) {
            copyAllProp(fields, originalObj, resultObj);
        } else {
            copyAccessibleProp(fields, originalObj, resultObj);
        }

        return resultObj;
    }

    /**
     * 拷贝fields里的所有属性, 包括私有属性, 拷贝到新对象中
     * @param fields
     * @param originalObj
     * @param resultObj
     */
    private static void copyAllProp(Field[] fields, Object originalObj, Object resultObj) {
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                field.set(resultObj, field.get(originalObj));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 拷贝所有被允许访问的属性到新对象里
     * @param fields
     * @param originalObj
     * @param resultObj
     */
    private static void copyAccessibleProp(Field[] fields, Object originalObj, Object resultObj) {
        for (Field field : fields) {
            if (field.isAccessible()) {
                try {
                    field.set(resultObj, field.get(originalObj));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
